package se.rende.schema2ical.client;

import java.util.ArrayList;
import java.util.List;

import se.rende.schema2ical.client.JsonParser.ArrayParser;
import se.rende.schema2ical.client.JsonParser.MapPair;
import se.rende.schema2ical.client.JsonParser.MapParser;

import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.i18n.client.DateTimeFormat;

public class StorageService {
	private static final String SAVE_SCHEMA_SERVLET_URL = GWT
			.getModuleBaseURL() + "saveSchema";
	private static final String LOAD_SCHEMA_SERVLET_URL = GWT
			.getModuleBaseURL() + "loadSchema";
	public static final DateTimeFormat schemaDateFormat = DateTimeFormat.getFormat("yyyy-MM-dd");

	/**
	 * Stores the schema on the server, by sending a http POST request to it,
	 * with the JSON coded schema.
	 * 
	 * @param schema
	 * @param storageResponse
	 */
	public void saveSchema(Schema schema, final StorageResponse<String> storageResponse) {
		StringBuilder sb = new StringBuilder();
		sb.append("{\n");
		sb.append("  startDate: '" + schema.getStartDate() + "',\n");
		sb.append("  passTimes: [\n");
		for (int i = 0; i < schema.getPassTimes().size(); i++) {
			PassTime passTime = schema.getPassTimes().get(i);
			sb.append("    {name: '" + passTime.getName() + "', "
					+ "fromTime: '" + passTime.getFromTime() + "', "
					+ "toTime: '" + passTime.getToTime() + "'}");
			if (i < schema.getPassTimes().size() - 1) {
				sb.append(",");
			}
			sb.append("\n");
		}
		sb.append("  ],\n");
		sb.append("  passes: '" + schema.getPasses() + "'\n");
		sb.append("}\n");

		// Send request to server and catch any errors.
		RequestBuilder builder = new RequestBuilder(RequestBuilder.POST,
				SAVE_SCHEMA_SERVLET_URL);
		try {
			builder.sendRequest(sb.toString(), new RequestCallback() {
				public void onError(Request request, Throwable exception) {
					storageResponse.failure("Couldn't retrieve JSON");
				}

				public void onResponseReceived(Request request,
						Response response) {
					if (200 == response.getStatusCode()) {
						storageResponse.success(null);
					} else {
						storageResponse.failure("Couldn't save schema ("
								+ response.getStatusText() + ")");
					}
				}
			});
		} catch (RequestException e) {
			storageResponse.failure("Couldn't retrieve JSON");
		}

	}

	public void loadSchema(final StorageResponse<Schema> storageResponse) {
		RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
				LOAD_SCHEMA_SERVLET_URL);
		try {
			builder.sendRequest(null, new RequestCallback() {
				public void onError(Request request, Throwable exception) {
					storageResponse.failure("Couldn't retrieve JSON");
				}

				public void onResponseReceived(Request request,
						Response response) {
					if (200 == response.getStatusCode()) {
						String responseText = response.getText();
						Schema schema = new Schema();
						parseJsonToSchema(responseText, schema);
						storageResponse.success(schema);
					} else {
						storageResponse.failure("Couldn't save schema ("
								+ response.getStatusText() + ")");
					}
				}

			});
		} catch (RequestException e) {
			storageResponse.failure("Couldn't retrieve JSON");
		}

	}

	public void parseJsonToSchema(String jsonText,	Schema schema) {
		JsonParser parser = new JsonParser(jsonText);
		MapParser mapParser = parser.getMapParser();
		while (mapParser.hasNext()) {
			MapPair pair = mapParser.getMapPair();
			if ("startDate".equals(pair.name)) {
				schema.setStartDate((String)pair.value);
			} else if ("passTimes".equals(pair.name)) {
				List<PassTime> passTimes = new ArrayList<PassTime>();
				ArrayParser ap = (ArrayParser) pair.value;
				while (ap.hasNext()) {
					MapParser mp = (MapParser) ap.get();
					String passName = (String) mp.getMapPair().value;
					String passStart = (String) mp.getMapPair().value;
					String passEnd = (String) mp.getMapPair().value;
					passTimes.add(new PassTime(passName.charAt(0), passStart, passEnd));
					mp.hasNext();
				}
				schema.setPassTimes(passTimes);
			} else if ("passes".equals(pair.name)) {
				schema.setPasses((String) pair.value);
			}
		}
	}
}
